home *** CD-ROM | disk | FTP | other *** search
- #include <string.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <unistd.h>
- #include <signal.h>
- #include <sys/socket.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <netinet/in.h>
- #include <netdb.h>
- #include <ioctl.h>
- #include <fcntl.h>
- #include <arpa/nameser.h> /* for <resolv.h> */
- #define __const const /* grrrr... */
- #include <resolv.h> /* for h_error */
- #include <mintbind.h>
- #include "global.h"
- #include "pipe.h"
-
-
- /* MiNTnet's fcntl(FIONREAD) returns this when the socket shuts down, or
- an error condition occurs, or there's no more to read. */
- #define NO_LIMIT 0x7FFFFFFFL
-
- typedef struct CIB_chain {
- int the_fd;
- #ifndef BLOCK_OPEN
- int established;
- #endif
- CIB the_CIB;
- struct CIB_chain *next;
- } CIB_chain;
-
- Daemon_Op OP;
- Daemon_Retval RET;
- CIB_chain *CIB_list = 0;
-
- static int daemon_pipe;
-
-
- int init_net()
- {
- if (Psemaphore(0, DMN_SEMAPHORE, 0L) < 0) {
- Cconws("Cannot get semaphore for daemon access\r\n");
- return 0;
- }
- /* We own the semaphores when they're created; release them so we can
- re-grab them later */
- Psemaphore(3, DMN_SEMAPHORE, 0L);
- #ifdef DEBUG
- if (Psemaphore(0, DEBUG_SEMAPHORE, 0L) < 0) {
- Cconws("Cannot get semaphore for debug log\r\n");
- return 0;
- }
- Psemaphore(3, DEBUG_SEMAPHORE, 0L);
- #endif
- return 1;
- }
-
-
- void dispatch()
- {
- PMSG pmsg;
- Daemon_Op *OP;
- Daemon_Retval *RET;
- int n;
-
- for (;;) {
- n = Pmsg(0, DMN_MBOX, &pmsg);
- if (n < 0) {
- exit(1);
- }
- OP = (Daemon_Op *)pmsg.userlong1;
- RET = (Daemon_Retval *)pmsg.userlong2;
- #ifdef DEBUG
- debug("sdsd", "Received op ", OP->common.op, " from pid ", pmsg.pid);
- #endif
-
- switch (OP->common.op) {
- case OP_TCP_OPEN:
- RET->ret_int16 = do_TCP_open(OP->P_TCP_open.hostaddr,
- OP->P_TCP_open.port, OP->P_TCP_open.tos,
- OP->P_TCP_open.obsize);
- break;
- case OP_TCP_CLOSE:
- RET->ret_int16 = do_TCP_close(OP->P_TCP_close.fd,
- OP->P_TCP_close.timeout);
- break;
- case OP_TCP_SEND:
- RET->ret_int16 = do_TCP_send(OP->P_TCP_send.fd, OP->P_TCP_send.buf,
- OP->P_TCP_send.buflen);
- break;
- case OP_TCP_WAIT_STATE:
- RET->ret_int16 = do_TCP_wait_state(OP->P_TCP_wait_state.fd,
- OP->P_TCP_wait_state.state,
- OP->P_TCP_wait_state.timeout);
- break;
- case OP_UDP_OPEN:
- RET->ret_int16 = do_UDP_open(OP->P_UDP_open.hostaddr,
- OP->P_UDP_open.port);
- break;
- case OP_UDP_CLOSE:
- RET->ret_int16 = do_UDP_close(OP->P_UDP_close.fd);
- break;
- case OP_UDP_SEND:
- RET->ret_int16 = do_UDP_send(OP->P_UDP_send.fd, OP->P_UDP_send.buf,
- OP->P_UDP_send.buflen);
- break;
- case OP_CNBYTE_COUNT:
- RET->ret_int16 = do_CNbyte_count(OP->P_CNbyte_count.fd);
- break;
- case OP_CNGET_CHAR:
- RET->ret_int16 = do_CNget_char(OP->P_CNget_char.fd);
- break;
- case OP_CNGET_NDB:
- RET->ret_NDBptr = do_CNget_NDB(OP->P_CNget_NDB.fd);
- break;
- case OP_CNGET_BLOCK:
- RET->ret_int16 = do_CNget_block(OP->P_CNget_block.fd,
- OP->P_CNget_block.buf,
- OP->P_CNget_block.len);
- break;
- case OP_RESOLVE:
- RET->ret_int16 = do_resolve(OP->P_resolve.hostname,
- OP->P_resolve.realname,
- OP->P_resolve.addrs,
- OP->P_resolve.naddrs);
- break;
- case OP_CNGETINFO:
- RET->ret_CIBptr = do_CNgetinfo(OP->P_CNgetinfo.fd);
- break;
- case OP_KRMALLOC:
- RET->ret_charptr = do_KRmalloc(OP->P_KRmalloc.size);
- break;
- case OP_KRFREE:
- do_KRfree(OP->P_KRfree.mem);
- RET->ret_int32 = 0;
- break;
- case OP_KRGETFREE:
- RET->ret_int32 = do_KRgetfree(OP->P_KRgetfree.flag);
- break;
- case OP_KRREALLOC:
- RET->ret_charptr = do_KRrealloc(OP->P_KRrealloc.mem,
- OP->P_KRrealloc.newsize);
- break;
- case OP_GETVSTR:
- RET->ret_charptr = do_getvstr(OP->P_KRfree.mem);
- break;
- default:
- #ifdef DEBUG
- debug("sd", "in dispatch(): unrecognized opcode ", OP->common.op);
- #endif
- break;
- }
- #ifdef DEBUG
- debug("sdsd", "Responding to op ", OP->common.op, " from pid ", pmsg.pid);
- #endif
- Pmsg(1, 0xFFFF0000L | pmsg.pid, &pmsg);
- continue;
- }
- }
-
-
- static int make_CIB(int fd, uint16 protocol, uint16 lport, uint16 rport,
- uint32 rhost, int established)
- {
- CIB_chain *C;
- int retval = 1;
-
- C = (CIB_chain *)do_KRmalloc(sizeof(CIB_chain));
- if (!C)
- retval = 0;
- else {
- C->the_fd = fd;
- #ifndef BLOCK_OPEN
- C->established = established;
- #endif
- C->the_CIB.protocol = protocol;
- C->the_CIB.lport = lport;
- C->the_CIB.rport = rport;
- C->the_CIB.rhost = rhost;
- C->next = CIB_list;
- CIB_list = C;
- }
- #ifdef DEBUG
- debug("si", "make_CIB() returns ", retval);
- #endif
- return retval;
- }
-
- static CIB *find_CIB(int fd)
- {
- register CIB_chain *C;
- CIB *CC = 0;
-
- for (C = CIB_list; C; C = C->next) {
- if (C->the_fd == fd) {
- CC = &(C->the_CIB);
- break;
- }
- }
- #ifdef DEBUG
- debug("sp", "find_CIB() returns ", (void *)CC);
- #endif
- return CC;
- }
-
- static void remove_CIB(int fd)
- {
- register CIB_chain *C = CIB_list, *C2;
-
- if (C && C->the_fd == fd) {
- CIB_list = C->next;
- do_KRfree(C);
- } else {
- for (C = CIB_list; C && C->next; C = C->next) {
- if (C->next->the_fd == fd) {
- C2 = C->next;
- C->next = C2->next;
- do_KRfree(C2);
- break;
- }
- }
- }
- #ifdef DEBUG
- debug("s", "remove_CIB() done");
- #endif
- }
-
- #ifndef BLOCK_OPEN
- /* Blech blech blech. I really don't like having to keep state info
- like this, but there appears to be no reliable way to get this info
- on the fly. */
- static int is_established(int fd)
- {
- register CIB_chain *C;
-
- for (C = CIB_list; C; C = C->next) {
- if (C->the_fd == fd) {
- break;
- }
- }
- #ifdef DEBUG
- debug("sdsss", "Connection ", fd, " is ",
- (C->established ? "" : "not "), "established");
- #endif
- return (C ? C->established : 0);
- }
-
- static void set_establish(int fd)
- {
- register CIB_chain *C;
-
- for (C = CIB_list; C; C = C->next) {
- if (C->the_fd == fd) {
- C->established = 1;
- break;
- }
- }
- }
- #endif /* BLOCK_OPEN */
-
-
- /* Incompatibility: obsize is ignored. MiNTnet does its own buffer
- handling. */
- int16 do_TCP_open(uint32 hostaddr, int16 port, int16 tos, uint16 obsize)
- {
- struct sockaddr_in addr;
- int fd;
- size_t scratch = sizeof(struct sockaddr_in);
-
- #ifdef DEBUG
- debug("slslslslsisisis", "Entering TCP_open(", (hostaddr>>24), ".",
- (hostaddr>>16)&0xFFL, ".", (hostaddr>>8)&0xFFL, ".", hostaddr&0xFFL,
- ", ", port, ", ", tos, ", ", obsize, ")");
- #endif
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = hostaddr;
- addr.sin_port = port;
-
- fd = socket(AF_INET, SOCK_STREAM, 0);
- if (fd < 0) {
- switch (errno) {
- case EMFILE:
- return E_NOCCB;
- case ENOMEM:
- return E_NOMEM;
- case ENOENT:
- case EAFNOSUPPORT:
- case ESOCKTNOSUPPORT:
- case EPROTONOSUPPORT:
- case EPROTOTYPE:
- return -1000 - errno;
- default:
- return E_CONNECTFAIL;
- }
- }
-
- if (hostaddr != 0) {
- #ifndef BLOCK_OPEN
- /* From the STiK specs: "TCP_open() returns immediately, without
- waiting for the connection to establish." */
- if (fcntl(fd, F_SETFL, O_NDELAY) < 0)
- return E_CONNECTFAIL;
- #endif
-
- if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
- switch (errno) {
- case EBADF:
- case EISCONN:
- return E_BADHANDLE;
- case EINVAL:
- return E_LISTEN;
- case ETIMEDOUT:
- return E_CNTIMEOUT;
- case ECONNREFUSED:
- return E_REFUSE;
- case EALREADY:
- case EINPROGRESS:
- case EINTR:
- break;
- case EAFNOSUPPORT:
- case EDESTADDRREQ:
- case EOPNOTSUPP:
- return -1000 - errno;
- default:
- return E_CONNECTFAIL;
- }
- }
-
- /* Cobble up the CIB structure for this connection. The only thing
- we don't yet have is the local port number. */
-
- if (getsockname(fd, (struct sockaddr *)&addr, &scratch) < 0) {
- int the_err = errno;
-
- close(fd);
- switch (the_err) {
- case EBADF:
- return E_BADHANDLE;
- case EINVAL:
- case EOPNOTSUPP:
- default:
- return -1000 - the_err;
- }
- }
- if (!make_CIB(fd, P_TCP, addr.sin_port, port, hostaddr, 0)) {
- close(fd);
- return E_NOMEM;
- }
-
- #ifdef DEBUG
- debug("si", "TCP_open() returns socket handle ", fd);
- #endif
- return fd;
- } else {
- int in_fd;
- size_t addr_size = sizeof(addr);
-
- /* From the STiK specs: "If rhost is 0, then the connection becomes
- a LISTEN socket, and waits for a connection request from a remote
- host." */
-
- addr.sin_addr.s_addr = INADDR_ANY;
-
- if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
- switch (errno) {
- case EBADF:
- case EADDRINUSE:
- case EINVAL:
- return E_BADHANDLE;
- case EAFNOSUPPORT:
- case EACCES:
- case EDESTADDRREQ:
- return -1000 - errno;
- default:
- return E_CONNECTFAIL;
- }
- }
-
- if (listen(fd, 5) < 0) {
- int the_err = errno;
-
- close(fd);
- switch (the_err) {
- case EBADF:
- return E_BADHANDLE;
- case EDESTADDRREQ:
- case EOPNOTSUPP:
- case EINVAL:
- return -1000 - the_err;
- default:
- return E_CONNECTFAIL;
- }
- }
-
- /* Incompatibility: I don't think I can emulate STiK's non-blocking
- LISTEN ports. STiK can apparently get away with this because it
- replaces the listen()'ed socket with the accept()'ed socket
- in situ; this behavior cannot be reproduced with Berkeley
- sockets. Hopefully this won't be too much of a problem. */
- if ((in_fd = accept(fd, (struct sockaddr *)&addr, &addr_size)) < 0) {
- int the_err = errno;
-
- close(fd);
- switch (the_err) {
- case EBADF:
- return E_BADHANDLE;
- case EMFILE:
- return E_NOCCB;
- case ENOMEM:
- return E_NOMEM;
- case EOPNOTSUPP:
- case EWOULDBLOCK:
- case ECONNABORTED:
- case EINVAL:
- case EINTR:
- return -1000 - the_err;
- default:
- return E_CONNECTFAIL;
- }
- }
-
- /* In STiK, an accept() apparently "eats" the listen()'ed socket; we
- emulate that by closing it. */
- close(fd);
-
- /* Cobble up the CIB structure for this connection. The only thing
- we don't yet have is the local port number. */
-
- if (getsockname(in_fd, (struct sockaddr *)&addr, &scratch) < 0) {
- int the_err = errno;
-
- close(in_fd);
- switch (the_err) {
- case EBADF:
- return E_BADHANDLE;
- case EINVAL:
- case EOPNOTSUPP:
- default:
- return -1000 - the_err;
- }
- }
- if (!make_CIB(in_fd, P_TCP, addr.sin_port, port, hostaddr, 1)) {
- close(in_fd);
- return E_NOMEM;
- }
-
- return in_fd;
- }
- }
-
- /* Incompatibility: timeout is ignored */
- int16 do_TCP_close(int16 fd, int16 timeout)
- {
- int ret;
-
- remove_CIB(fd);
- ret = close(fd);
- #ifdef DEBUG
- debug("sisi", "TCP_close(", fd, ") returns ", (ret < 0 ? E_BADCLOSE : 0));
- #endif
- if (ret < 0)
- return E_BADCLOSE;
- else return 0;
- }
-
- /* Incompatibility: TCP_send() will probably be blocking; after all, I
- can't return E_OBUFFULL in good faith if I don't honor obsize from
- TCP_open(). */
- /* Incompatibility: What is TCP_send() supposed to do if the non-blocking
- TCP_open() hasn't finished? The STiK specs don't give a clue; I'm
- gonna just turn off O_NDELAY and wait for the connection to establish. */
- int16 do_TCP_send(int16 fd, char* buf, int16 buflen)
- {
- int n, tot = 0;
-
- #ifdef DEBUG
- debug("sSs", "in TCP_send(\"", buflen, buf, "\")");
- #endif
-
- #ifndef BLOCK_OPEN
- if (!is_established(fd))
- do_TCP_wait_state(fd, 0, 0);
- #endif
-
- for (;;) {
- n = write(fd, buf + tot, buflen - tot);
- if (n < 0) {
- switch (errno) {
- case EBADF:
- return E_BADHANDLE;
- case ENOSPC:
- return E_NOMEM;
- case ENXIO:
- return E_LOSTCARRIER;
- /* case EAGAIN: */
- case ERANGE:
- return E_OBUFFULL;
- default:
- return -1000 - errno;
- }
- } else {
- tot += n;
- if (tot >= buflen)
- return E_NORMAL;
- }
- }
- }
-
- /* Incompatibility: Yeah, right, like I could reproduce the behavior of
- this function... Just select() on the socket; this works for waiting
- for the non-blocking open to complete, which is probably the only
- thing it gets used for. */
- int16 do_TCP_wait_state(int16 fd, int16 state, int16 timeout)
- {
- auto fd_set read_set, write_set, except_set;
- struct timeval T;
- int n;
-
- #ifdef DEBUG
- debug("s", "in TCP_wait_state()");
- #endif
-
- #ifndef BLOCK_OPEN
- if (is_established(fd))
- return E_NORMAL;
-
- n = fcntl(fd, F_GETFL);
- fcntl(fd, F_SETFL, n & ~O_NDELAY);
-
- FD_ZERO(&read_set);
- FD_SET(fd, &read_set);
- FD_ZERO(&write_set);
- FD_SET(fd, &write_set);
- FD_ZERO(&except_set);
- FD_SET(fd, &except_set);
- T.tv_sec = timeout;
- T.tv_usec = 0;
-
- n = select(fd + 1, &read_set, &write_set, &except_set, &T);
- if (n == 0)
- return E_USERTIMEOUT;
- if (n > 0) {
- set_establish(fd);
- return E_NORMAL;
- }
- switch (errno) {
- case EBADF:
- return E_BADHANDLE;
- case EINTR:
- case EINVAL:
- default:
- return -1000 - errno;
- }
- #else
- return E_NORMAL;
- #endif /* BLOCK_OPEN */
- }
-
- int16 do_UDP_open(uint32 hostaddr, int16 port)
- {
- struct sockaddr_in addr;
- int fd;
- size_t scratch = sizeof(struct sockaddr_in);
-
- #ifdef DEBUG
- debug("s", "in UDP_open()");
- #endif
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = hostaddr;
- addr.sin_port = port;
- memset(addr.sin_zero, 0, 8);
-
- fd = socket(AF_UNIX, SOCK_DGRAM, IPPROTO_UDP);
- if (fd < 0) {
- switch (errno) {
- case EMFILE:
- return E_NOCCB;
- case ENOMEM:
- return E_NOMEM;
- case ENOENT:
- case EAFNOSUPPORT:
- case ESOCKTNOSUPPORT:
- case EPROTONOSUPPORT:
- case EPROTOTYPE:
- return -1000 - errno;
- default:
- return E_CONNECTFAIL;
- }
- }
-
- if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
- int the_err = errno;
-
- close(fd);
- switch (the_err) {
- case EBADF:
- case EISCONN:
- return E_BADHANDLE;
- case EINVAL:
- return E_LISTEN;
- case ETIMEDOUT:
- return E_CNTIMEOUT;
- case ECONNREFUSED:
- return E_REFUSE;
- case EALREADY:
- case EINPROGRESS:
- case EINTR:
- return fd;
- case EAFNOSUPPORT:
- case EDESTADDRREQ:
- case EOPNOTSUPP:
- return -1000 - the_err;
- default:
- return E_CONNECTFAIL;
- }
- }
-
- /* Cobble up the CIB structure for this connection. The only thing
- we don't yet have is the local port number. */
-
- if (getsockname(fd, (struct sockaddr *)&addr, &scratch) < 0) {
- int the_err = errno;
-
- close(fd);
- switch (the_err) {
- case EBADF:
- return E_BADHANDLE;
- case EINVAL:
- case EOPNOTSUPP:
- default:
- return -1000 - the_err;
- }
- }
- if (!make_CIB(fd, P_UDP, addr.sin_port, port, hostaddr, 1)) {
- close(fd);
- return E_NOMEM;
- }
-
- return fd;
- }
-
- int16 do_UDP_close(int16 fd)
- {
- int ret;
-
- #ifdef DEBUG
- debug("s", "in UDP_close()");
- #endif
- remove_CIB(fd);
- ret = close(fd);
- if (ret < 0)
- return E_BADCLOSE;
- else return 0;
- }
-
- int16 do_UDP_send(int16 fd, char* buf, int16 buflen)
- {
- int n, tot = 0;
-
- #ifdef DEBUG
- debug("s", "in UDP_send()");
- #endif
- n = write(fd, buf + tot, buflen - tot);
- if (n < 0) {
- switch (errno) {
- case EBADF:
- return E_BADHANDLE;
- case ENOSPC:
- return E_NOMEM;
- case ENXIO:
- return E_LOSTCARRIER;
- case ERANGE:
- return E_OBUFFULL;
- default:
- return -1000 - errno;
- }
- } else {
- return E_NORMAL;
- }
- }
-
- /* This is just an estimate, but it should work. */
- int16 do_CNbyte_count(int16 fd)
- {
- long l;
-
- if (fcntl(fd, FIONREAD, &l) < 0)
- return -1000 - errno;
- if (l == NO_LIMIT) {
- #ifndef BLOCK_OPEN
- /* Tricky. This could be either EOF or the connection not
- established. In the latter case, we have the "0 or E_NODATA?"
- puzzler from below. */
- if (!is_established(fd)) {
- return 0;
- }
- #endif
- return E_EOF;
- }
- /* Now here's a puzzler. If there's no data available should I return
- 0 or E_NODATA? Dan Ackerman's mailer assumes the former, so that's
- what I'll do. */
- if (l == 0) {
- /* Here's a sneaky trick: If there's no data, surrender the rest of
- our timeslice so that the STiK app doesn't eat all CPU time
- spinning its wheels. */
- Syield();
- return 0;
- }
- #ifdef DEBUG
- debug("sdsl", "CNbyte_count(", fd, ") returns ", l);
- #endif
- #ifndef BLOCK_OPEN
- /* I really don't like doing this here, since this function will
- likely be called in a tight loop, but it has to be done, and this
- is about the only place I can do it. */
- set_establish(fd);
- #endif
- return l;
- }
-
- /* There should probably be a more efficient way of doing this than
- calling read() */
- int16 do_CNget_char(int16 fd)
- {
- char c;
- int n;
-
- n = read(fd, &c, 1);
- if (n > 0) {
- #ifndef BLOCK_OPEN
- /* Again, I don't really like doing this here, but I don't think I
- can avoid it. */
- set_establish(fd);
- #endif
- #ifdef DEBUG
- debug("sdscsxs", "CNget_char(", fd, ") returns '", c, "' (0x",
- (unsigned)c, ")");
- #endif
- return c;
- }
- if (n == 0) {
- #ifdef DEBUG
- debug("sds", "CNget_char(", fd, ") returns EOF");
- #endif
- return E_EOF;
- }
- #ifdef DEBUG
- debug("sdsd", "CNget_char(", fd, ") gets error code ", errno);
- #endif
- switch (errno) {
- case EWOULDBLOCK:
- return E_NODATA;
- case EBADF:
- return E_BADHANDLE;
- default:
- return -1000 - errno;
- }
- }
-
- /* We fake this by reading whatever is there and building a a fake NDB
- for it */
- NDB* do_CNget_NDB(int16 fd)
- {
- int bufsize = do_CNbyte_count(fd);
- char *buf;
- NDB *ndb = 0;
-
- if (bufsize <= 0) {
- return 0;
- }
- buf = do_KRmalloc(bufsize);
- if (!buf) {
- return 0;
- }
- ndb = (NDB *)do_KRmalloc(sizeof(NDB));
- if (!ndb) {
- do_KRfree(buf);
- return 0;
- }
- bufsize = read(fd, buf, bufsize);
- if (bufsize <= 0) {
- do_KRfree(buf);
- do_KRfree((char *)ndb);
- return 0;
- }
- ndb->ptr = ndb->ndata = buf;
- ndb->len = bufsize;
- ndb->next = 0;
- #ifdef DEBUG
- debug("sdsss", "CNget_NDB(", fd, ") returns |", ndb->ndata, "|");
- #endif
- return ndb;
- }
-
- /* Incompatibility: CNget_block() is blocking, because there's no way
- to say to MiNTnet, "If you can't fill the entire buffer in one try,
- don't read anything" */
- int16 do_CNget_block(int16 fd, char* buf, int16 len)
- {
- int n, tot = 0;
-
- #ifndef BLOCK_OPEN
- if (!is_established(fd))
- do_TCP_wait_state(fd, 0, 0);
- #endif
-
- for (;;) {
- n = read(fd, buf + tot, len - tot);
- if (n > 0) {
- tot += n;
- if (tot >= len) {
- #ifdef DEBUG
- debug("sisisss", "CNget_block(", fd, ", ", len, ") reads |", buf,
- "|");
- #endif
- return tot;
- }
- } else if (n == 0) {
- /* Incompatibility: If we read part of the buffer before getting
- the EOF, there's no way to "unread" the read data. I'm torn
- between returning the number of bytes actually read and
- trusting the caller to notice, or returning E_EOF and
- discarding the partial buffer. For now, I'll do the former. */
- return tot;
- } else {
- switch (errno) {
- case EWOULDBLOCK:
- return E_NODATA;
- case EBADF:
- return E_BADHANDLE;
- default:
- return -1000 - errno;
- }
- }
- }
- }
-
- int16 do_resolve(char *hostname, char **realname, uint32 *addrs, int16 naddrs)
- {
- register struct hostent *H = 0;
- register char **raddr;
- register int i;
-
- #ifdef DEBUG
- debug("ssspspsis", "in resolve(\"", hostname, "\", ", (void *)realname,
- ", ", (void *)addrs, ", ", naddrs, ")");
- #endif
- H = gethostbyname(hostname);
- if (!H) {
- #ifdef DEBUG
- debug("s", "gethostbyname() returns NULL");
- #endif
- switch (h_errno) {
- case HOST_NOT_FOUND:
- return E_NOHOSTNAME;
- case NO_DATA:
- return E_DNSNOADDR;
- case TRY_AGAIN:
- case NO_RECOVERY:
- default:
- return E_CANTRESOLVE;
- }
- }
- #ifdef DEBUG
- debug("sp", " gethostbyname() returns ", (void *)H);
- #endif
-
- if (realname) {
- #ifdef DEBUG
- debug("sss", " copying name \"", H->h_name, "\"");
- #endif
- *realname = do_KRmalloc(strlen(H->h_name) + 1);
- strcpy(*realname, H->h_name);
- }
- /* BUG: assumes addresses returned have type struct in_addr */
- for (i = 0, raddr = H->h_addr_list; *raddr && i < naddrs; i++, raddr++) {
- #ifdef DEBUG
- debug("sXsi",
- " copying address ", ((struct in_addr *)(*raddr))->s_addr,
- " to array elmt ", i);
- #endif
- addrs[i] = ((struct in_addr *)(*raddr))->s_addr;
- }
-
- #ifdef DEBUG
- debug("si", " returning ", i);
- #endif
- return i;
- }
-
- /* (possible) Incompatibility: It is possible, at least in theory, for
- find_CIB() to return NULL; the STiK specs seem to imply that this
- cannot happen, so the receiving app probably doesn't check for it.
- In practice, find_CIB() should not return NULL, except for file
- descriptors that aren't sockets opened by GlueSTiK. */
- CIB* do_CNgetinfo(int16 fd)
- {
- #ifdef DEBUG
- debug("s", "in do_CNgetinfo()");
- #endif
- return find_CIB(fd);
- }
-